home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Graphics Programming (2nd Edition) / Visual Basic Graphics Programming 2nd Edition.iso / Src / Ch16 / FaceGou.cls < prev    next >
Text File  |  1999-06-28  |  19KB  |  648 lines

  1. VERSION 1.0 CLASS
  2. BEGIN
  3.   MultiUse = -1  'True
  4.   Persistable = 0  'NotPersistable
  5.   DataBindingBehavior = 0  'vbNone
  6.   DataSourceBehavior  = 0  'vbNone
  7.   MTSTransactionMode  = 0  'NotAnMTSObject
  8. END
  9. Attribute VB_Name = "Face3d"
  10. Attribute VB_GlobalNameSpace = False
  11. Attribute VB_Creatable = False
  12. Attribute VB_PredeclaredId = False
  13. Attribute VB_Exposed = False
  14. Option Explicit
  15.  
  16. ' Point3D is defined in module M3OPS.BAS as:
  17. '    Type Point3D
  18. '        coord(1 To 4) As Single
  19. '        trans(1 To 4) As Single
  20. '    End Type
  21.  
  22. Public NumPts As Long           ' Number of points.
  23. Private Points() As Point3D     ' Data points.
  24.  
  25. Public NumNormals As Long       ' Number of vertex normals.
  26. Private Normals() As Point3D    ' Vertex normals.
  27.  
  28. Public IsCulled As Boolean
  29.  
  30. Private Type POINTAPI
  31.     X As Long
  32.     Y As Long
  33. End Type
  34. Private Declare Function Polygon Lib "gdi32" (ByVal hdc As Long, lpPoint As POINTAPI, ByVal nCount As Long) As Long
  35. Private Declare Function CreatePolygonRgn Lib "gdi32" (lpPoint As POINTAPI, ByVal nCount As Long, ByVal nPolyFillMode As Long) As Long
  36. Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
  37. Private Declare Function PtInRegion Lib "gdi32" (ByVal hRgn As Long, ByVal X As Long, ByVal Y As Long) As Long
  38. Private Const ALTERNATE = 1
  39. Private Declare Function GetRgnBox Lib "gdi32" (ByVal hRgn As Long, lpRect As RECT) As Long
  40. Private Type RECT
  41.     Left As Long
  42.     Top As Long
  43.     Right As Long
  44.     Bottom As Long
  45. End Type
  46.  
  47. ' Diffuse reflection coefficients.
  48. Public DiffuseKr As Single
  49. Public DiffuseKg As Single
  50. Public DiffuseKb As Single
  51.  
  52. ' Ambient light coefficients.
  53. Public AmbientKr As Single
  54. Public AmbientKg As Single
  55. Public AmbientKb As Single
  56.  
  57. ' Specular reflection coefficients.
  58. Public SpecularK As Single
  59. Public SpecularN As Single
  60. ' Return True if this polygon partially obscures
  61. ' (has greater Z value than) polygon target.
  62. '
  63. ' We assume one polygon may obscure the other, but
  64. ' they cannot obscure each other.
  65. '
  66. ' This check is executed by seeing where the
  67. ' projections of the edges of the polygons cross.
  68. ' Where they cross, see if one Z value is greater
  69. ' than the other.
  70. '
  71. ' If no edges cross, see if one polygon contains
  72. ' the other. If so, there is an overlap.
  73. Public Function Obscures(ByVal target As Face3d) As Boolean
  74. Dim num As Integer
  75. Dim i As Integer
  76. Dim j As Integer
  77. Dim xi1 As Single
  78. Dim yi1 As Single
  79. Dim zi1 As Single
  80. Dim xi2 As Single
  81. Dim yi2 As Single
  82. Dim zi2 As Single
  83. Dim xj1 As Single
  84. Dim yj1 As Single
  85. Dim zj1 As Single
  86. Dim xj2 As Single
  87. Dim yj2 As Single
  88. Dim zj2 As Single
  89. Dim X As Single
  90. Dim Y As Single
  91. Dim z1 As Single
  92. Dim z2 As Single
  93.  
  94.     num = target.NumPts
  95.  
  96.     ' Check each edge in this polygon.
  97.     GetTransformedPoint NumPts, xi1, yi1, zi1
  98.     For i = 1 To NumPts
  99.         GetTransformedPoint i, xi2, yi2, zi2
  100.  
  101.         ' Compare with each edge in the other.
  102.         target.GetTransformedPoint num, xj1, yj1, zj1
  103.         For j = 1 To num
  104.             target.GetTransformedPoint j, xj2, yj2, zj2
  105.             ' See if the segments cross.
  106.             If FindCrossing( _
  107.                 xi1, yi1, zi1, _
  108.                 xi2, yi2, zi2, _
  109.                 xj1, yj1, zj1, _
  110.                 xj2, yj2, zj2, _
  111.                 X, Y, z1, z2) _
  112.             Then
  113.                 If z1 - z2 > 0.01 Then
  114.                     ' z1 > z2. We obscure it.
  115.                     Obscures = True
  116.                     Exit Function
  117.                 End If
  118.                 If z2 - z1 > 0.01 Then
  119.                     ' z2 > z1. It obscures us.
  120.                     Obscures = False
  121.                     Exit Function
  122.                 End If
  123.             End If
  124.  
  125.             xj1 = xj2
  126.             yj1 = yj2
  127.             zj1 = zj2
  128.         Next j
  129.  
  130.         xi1 = xi2
  131.         yi1 = yi2
  132.         zi1 = zi2
  133.     Next i
  134.     
  135.     ' No edges cross. See if one polygon contains
  136.     ' the other.
  137.  
  138.     ' If any points of one polygon are inside the
  139.     ' other, then they must all be. Since the
  140.     ' IsAbove tests were inconclusive, some points
  141.     ' in one polygon are on the "bad" side of the
  142.     ' other. In that case there is an overlap.
  143.  
  144.     ' See if this polygon is inside the other.
  145.     GetTransformedPoint 1, xi1, yi1, zi1
  146.     If target.PointInside(xi1, yi1) Then
  147.         Obscures = True
  148.         Exit Function
  149.     End If
  150.  
  151.     ' See if the other polygon is inside this one.
  152.     target.GetTransformedPoint 1, xi1, yi1, zi1
  153.     If PointInside(xi1, yi1) Then
  154.         Obscures = True
  155.         Exit Function
  156.     End If
  157.  
  158.     Obscures = False
  159. End Function
  160. ' See where the projections of two segments cross.
  161. ' Return true if the segments cross, false
  162. ' otherwise.
  163. Private Function FindCrossing( _
  164.     ByVal ax1 As Single, ByVal ay1 As Single, ByVal az1 As Single, _
  165.     ByVal ax2 As Single, ByVal ay2 As Single, ByVal az2 As Single, _
  166.     ByVal bx1 As Single, ByVal by1 As Single, ByVal bz1 As Single, _
  167.     ByVal bx2 As Single, ByVal by2 As Single, ByVal bz2 As Single, _
  168.     ByRef X As Single, ByRef Y As Single, ByRef z1 As Single, ByRef z2 As Single) _
  169.         As Boolean
  170. Dim dxa As Single
  171. Dim dya As Single
  172. Dim dza As Single
  173. Dim dxb As Single
  174. Dim dyb As Single
  175. Dim dzb As Single
  176. Dim t1 As Single
  177. Dim t2 As Single
  178. Dim denom As Single
  179.  
  180.     dxa = ax2 - ax1
  181.     dya = ay2 - ay1
  182.     dxb = bx2 - bx1
  183.     dyb = by2 - by1
  184.     
  185.     FindCrossing = False
  186.     
  187.     denom = dxb * dya - dyb * dxa
  188.     ' If the segments are parallel, stop.
  189.     If denom < 0.01 And denom > -0.01 Then Exit Function
  190.  
  191.     t2 = (ax1 * dya - ay1 * dxa - bx1 * dya + by1 * dxa) / denom
  192.     If t2 < 0 Or t2 > 1 Then Exit Function
  193.     
  194.     t1 = (ax1 * dyb - ay1 * dxb - bx1 * dyb + by1 * dxb) / denom
  195.     If t1 < 0 Or t1 > 1 Then Exit Function
  196.  
  197.     ' Compute the points of overlap.
  198.     X = ax1 + t1 * dxa
  199.     Y = ay1 + t1 * dya
  200.     dza = az2 - az1
  201.     dzb = bz2 - bz1
  202.     z1 = az1 + t1 * dza
  203.     z2 = bz1 + t2 * dzb
  204.     FindCrossing = True
  205. End Function
  206.  
  207. ' Return True if the point projection lies within
  208. ' this polygon's projection.
  209. Public Function PointInside(ByVal X As Single, ByVal Y As Single) As Boolean
  210. Dim i As Integer
  211. Dim theta1 As Double
  212. Dim theta2 As Double
  213. Dim dtheta As Double
  214. Dim dx As Double
  215. Dim dy As Double
  216. Dim angles As Double
  217.  
  218.     dx = Points(NumPts).trans(1) - X
  219.     dy = Points(NumPts).trans(2) - Y
  220.     theta1 = ATan2(CSng(dy), CSng(dx))
  221.     If theta1 < 0 Then theta1 = theta1 + 2 * PI
  222.     For i = 1 To NumPts
  223.         dx = Points(i).trans(1) - X
  224.         dy = Points(i).trans(2) - Y
  225.         theta2 = ATan2(CSng(dy), CSng(dx))
  226.         If theta2 < 0 Then theta2 = theta2 + 2 * PI
  227.         dtheta = theta2 - theta1
  228.         If dtheta > PI Then dtheta = dtheta - 2 * PI
  229.         If dtheta < -PI Then dtheta = dtheta + 2 * PI
  230.         angles = angles + dtheta
  231.         theta1 = theta2
  232.     Next i
  233.  
  234.     PointInside = (Abs(angles) > 0.001)
  235. End Function
  236.  
  237. ' Return True if this polygon is completly above
  238. ' the plane containing target.
  239. Public Function IsAbove(ByVal target As Face3d) As Boolean
  240. Dim Nx As Single
  241. Dim Ny As Single
  242. Dim Nz As Single
  243. Dim px As Single
  244. Dim py As Single
  245. Dim pz As Single
  246. Dim dx As Single
  247. Dim dy As Single
  248. Dim dz As Single
  249. Dim Cx As Single
  250. Dim Cy As Single
  251. Dim Cz As Single
  252. Dim i As Integer
  253.  
  254.     ' Compute an upward pointing normal to the plane.
  255.     target.TransformedNormalVector Nx, Ny, Nz
  256.     If Nz < 0 Then
  257.         Nx = -Nx
  258.         Ny = -Ny
  259.         Nz = -Nz
  260.     End If
  261.  
  262.     ' Get a point on the plane.
  263.     target.GetTransformedPoint 1, px, py, pz
  264.  
  265.     ' See if the points in this polygon all lie
  266.     ' above the plane containing target.
  267.     For i = 1 To NumPts
  268.         ' Get the vector from plane to point.
  269.         dx = Points(i).trans(1) - px
  270.         dy = Points(i).trans(2) - py
  271.         dz = Points(i).trans(3) - pz
  272.  
  273.         ' If the dot product < 0, the point is
  274.         ' below the plane.
  275.         If dx * Nx + dy * Ny + dz * Nz < -0.01 Then
  276.             IsAbove = False
  277.             Exit Function
  278.         End If
  279.     Next i
  280.     IsAbove = True
  281. End Function
  282. ' Return true if this polygon is completly below
  283. ' the plane containing target.
  284. Public Function IsBelow(ByVal target As Face3d) As Boolean
  285. Dim Nx As Single
  286. Dim Ny As Single
  287. Dim Nz As Single
  288. Dim px As Single
  289. Dim py As Single
  290. Dim pz As Single
  291. Dim dx As Single
  292. Dim dy As Single
  293. Dim dz As Single
  294. Dim Cx As Single
  295. Dim Cy As Single
  296. Dim Cz As Single
  297. Dim i As Integer
  298.  
  299.     ' Compute a downward pointing normal to the plane.
  300.     target.TransformedNormalVector Nx, Ny, Nz
  301.     If Nz > 0 Then
  302.         Nx = -Nx
  303.         Ny = -Ny
  304.         Nz = -Nz
  305.     End If
  306.  
  307.     ' Get a point on the plane.
  308.     target.GetTransformedPoint 1, px, py, pz
  309.  
  310.     ' See if the points in this polygon all lie
  311.     ' below the plane containing target.
  312.     For i = 1 To NumPts
  313.         ' Get the vector from plane to point.
  314.         dx = Points(i).trans(1) - px
  315.         dy = Points(i).trans(2) - py
  316.         dz = Points(i).trans(3) - pz
  317.  
  318.         ' If the dot product < 0, the point is
  319.         ' below the plane.
  320.         If dx * Nx + dy * Ny + dz * Nz < -0.01 Then
  321.             IsBelow = False
  322.             Exit Function
  323.         End If
  324.     Next i
  325.     IsBelow = True
  326. End Function
  327. ' Return the transformed coordinates of a point
  328. ' on the polygon.
  329. Public Sub GetTransformedPoint(ByVal Index As Long, ByRef X As Single, ByRef Y As Single, ByRef Z As Single)
  330.     X = Points(Index).trans(1)
  331.     Y = Points(Index).trans(2)
  332.     Z = Points(Index).trans(3)
  333. End Sub
  334. ' Return the bounds of this polygon.
  335. Public Sub GetExtent(ByRef xmin As Single, ByRef xmax As Single, ByRef ymin As Single, ByRef ymax As Single, ByRef zmin As Single, ByRef zmax As Single)
  336. Dim i As Integer
  337.  
  338.     If NumPts < 1 Then Exit Sub
  339.  
  340.     With Points(1)
  341.         xmin = .trans(1)
  342.         xmax = xmin
  343.         ymin = .trans(2)
  344.         ymax = ymin
  345.         zmin = .trans(3)
  346.         zmax = zmin
  347.     End With
  348.  
  349.     For i = 2 To NumPts
  350.         With Points(i)
  351.             If xmin > .trans(1) Then xmin = .trans(1)
  352.             If xmax < .trans(1) Then xmax = .trans(1)
  353.             If ymin > .trans(2) Then ymin = .trans(2)
  354.             If ymax < .trans(2) Then ymax = .trans(2)
  355.             If zmin > .trans(3) Then zmin = .trans(3)
  356.             If zmax < .trans(3) Then zmax = .trans(3)
  357.         End With
  358.     Next i
  359. End Sub
  360.  
  361.  
  362. ' Compute a normal vector for this polygon.
  363. Public Sub NormalVector(ByRef Nx As Single, ByRef Ny As Single, ByRef Nz As Single)
  364. Dim Ax As Single
  365. Dim Ay As Single
  366. Dim Az As Single
  367. Dim Bx As Single
  368. Dim By As Single
  369. Dim Bz As Single
  370.  
  371.     Ax = Points(2).coord(1) - Points(1).coord(1)
  372.     Ay = Points(2).coord(2) - Points(1).coord(2)
  373.     Az = Points(2).coord(3) - Points(1).coord(3)
  374.     Bx = Points(3).coord(1) - Points(2).coord(1)
  375.     By = Points(3).coord(2) - Points(2).coord(2)
  376.     Bz = Points(3).coord(3) - Points(2).coord(3)
  377.     m3Cross Nx, Ny, Nz, Ax, Ay, Az, Bx, By, Bz
  378. End Sub
  379. ' Compute a unit normal vector for this polygon.
  380. Public Sub UnitNormalVector(ByRef Nx As Single, ByRef Ny As Single, ByRef Nz As Single)
  381. Dim Length As Single
  382.  
  383.     NormalVector Nx, Ny, Nz
  384.     Length = Sqr(Nx * Nx + Ny * Ny + Nz * Nz)
  385.     Nx = Nx / Length
  386.     Ny = Ny / Length
  387.     Nz = Nz / Length
  388. End Sub
  389.  
  390. ' Return the proper shade for this face
  391. ' due to the indicated light source.
  392. Private Function SurfaceColor(ByVal light_sources As Collection, ByVal ambient_light As Integer, ByVal eye_x As Single, ByVal eye_y As Single, ByVal eye_z As Single) As Long
  393. Dim Nx As Single
  394. Dim Ny As Single
  395. Dim Nz As Single
  396.  
  397.     ' Find the unit surface normal.
  398.     UnitNormalVector Nx, Ny, Nz
  399.  
  400.     ' Calculate the color value.
  401.     SurfaceColor = CalculateSurfaceColor( _
  402.         Points(1).coord(1), Points(1).coord(2), Points(1).coord(3), _
  403.         Nx, Ny, Nz, light_sources, ambient_light, _
  404.         eye_x, eye_y, eye_z, _
  405.         DiffuseKr, DiffuseKg, DiffuseKb, _
  406.         AmbientKr, AmbientKg, AmbientKb, _
  407.         SpecularK, SpecularN)
  408. End Function
  409. ' Compute a transformed normal vector for this polygon.
  410. Public Sub TransformedNormalVector(ByRef Nx As Single, ByRef Ny As Single, ByRef Nz As Single)
  411. Dim Ax As Single
  412. Dim Ay As Single
  413. Dim Az As Single
  414. Dim Bx As Single
  415. Dim By As Single
  416. Dim Bz As Single
  417.  
  418.     Ax = Points(2).trans(1) - Points(1).trans(1)
  419.     Ay = Points(2).trans(2) - Points(1).trans(2)
  420.     Az = Points(2).trans(3) - Points(1).trans(3)
  421.     Bx = Points(3).trans(1) - Points(2).trans(1)
  422.     By = Points(3).trans(2) - Points(2).trans(2)
  423.     Bz = Points(3).trans(3) - Points(2).trans(3)
  424.     m3Cross Nx, Ny, Nz, Ax, Ay, Az, Bx, By, Bz
  425. End Sub
  426.  
  427.  
  428. ' Add one or more points to the polygon.
  429. Public Sub AddPoints(ParamArray coord() As Variant)
  430. Dim num_pts As Integer
  431. Dim i As Integer
  432. Dim pt As Integer
  433.  
  434.     num_pts = (UBound(coord) + 1) \ 3
  435.     ReDim Preserve Points(1 To NumPts + num_pts)
  436.  
  437.     pt = 0
  438.     For i = 1 To num_pts
  439.         Points(NumPts + i).coord(1) = coord(pt)
  440.         Points(NumPts + i).coord(2) = coord(pt + 1)
  441.         Points(NumPts + i).coord(3) = coord(pt + 2)
  442.         Points(NumPts + i).coord(4) = 1#
  443.         pt = pt + 3
  444.     Next i
  445.  
  446.     NumPts = NumPts + num_pts
  447. End Sub
  448. ' Add one or more vertex normals to the polygon.
  449. ' Normalize the vectors.
  450. Public Sub AddNormals(ParamArray coord() As Variant)
  451. Dim num_pts As Integer
  452. Dim i As Integer
  453. Dim pt As Integer
  454. Dim X As Single
  455. Dim Y As Single
  456. Dim Z As Single
  457. Dim Length As Single
  458.  
  459.     num_pts = (UBound(coord) + 1) \ 3
  460.     ReDim Preserve Normals(1 To NumNormals + num_pts)
  461.  
  462.     pt = 0
  463.     For i = 1 To num_pts
  464.         X = coord(pt)
  465.         Y = coord(pt + 1)
  466.         Z = coord(pt + 2)
  467.         Length = Sqr(X * X + Y * Y + Z * Z)
  468.         Normals(NumNormals + i).coord(1) = X / Length
  469.         Normals(NumNormals + i).coord(2) = Y / Length
  470.         Normals(NumNormals + i).coord(3) = Z / Length
  471.         Normals(NumNormals + i).coord(4) = 1#
  472.         pt = pt + 3
  473.     Next i
  474.  
  475.     NumNormals = NumNormals + num_pts
  476. End Sub
  477.  
  478. ' Apply a transformation matrix which may not
  479. ' contain 0, 0, 0, 1 in the last column to the
  480. ' object.
  481. Public Sub ApplyFull(M() As Single)
  482. Dim i As Integer
  483.  
  484.     ' Do nothing if we are culled.
  485.     If IsCulled Then Exit Sub
  486.  
  487.     For i = 1 To NumPts
  488.         m3ApplyFull Points(i).coord, M, Points(i).trans
  489.     Next i
  490. End Sub
  491.  
  492. ' Apply a transformation matrix to the object.
  493. Public Sub Apply(M() As Single)
  494. Dim i As Integer
  495.  
  496.     ' Do nothing if we are culled.
  497.     If IsCulled Then Exit Sub
  498.  
  499.     For i = 1 To NumPts
  500.         m3Apply Points(i).coord, M, Points(i).trans
  501.     Next i
  502. End Sub
  503.  
  504. ' Draw the transformed points on a Form, Printer,
  505. ' or PictureBox.
  506. Public Sub Draw(ByVal pic As PictureBox, ByVal light_sources As Collection, ByVal ambient_light As Integer, ByVal eye_x As Single, ByVal eye_y As Single, ByVal eye_z As Single)
  507. Dim x4 As Single
  508. Dim y4 As Single
  509. Dim z4 As Single
  510. Dim Nx4 As Single
  511. Dim Ny4 As Single
  512. Dim Nz4 As Single
  513. Dim Tx4 As Single
  514. Dim Ty4 As Single
  515.  
  516.     ' Do nothing if we are culled.
  517.     If IsCulled Then Exit Sub
  518.     If NumPts < 3 Then Exit Sub
  519.     If NumPts > 4 Then Exit Sub
  520.  
  521.     ' Make sure we have 4 points.
  522.     If NumPts < 4 Then
  523.         x4 = Points(3).coord(1)
  524.         y4 = Points(3).coord(2)
  525.         z4 = Points(3).coord(3)
  526.         Nx4 = Normals(3).coord(1)
  527.         Ny4 = Normals(3).coord(2)
  528.         Nz4 = Normals(3).coord(3)
  529.         Tx4 = Points(3).trans(1)
  530.         Ty4 = Points(3).trans(2)
  531.     Else
  532.         x4 = Points(4).coord(1)
  533.         y4 = Points(4).coord(2)
  534.         z4 = Points(4).coord(3)
  535.         Nx4 = Normals(4).coord(1)
  536.         Ny4 = Normals(4).coord(2)
  537.         Nz4 = Normals(4).coord(3)
  538.         Tx4 = Points(4).trans(1)
  539.         Ty4 = Points(4).trans(2)
  540.     End If
  541.  
  542.     ' Shade the quadrilateral.
  543.     GouraudQuadrilateral pic, light_sources, _
  544.         ambient_light, eye_x, eye_y, eye_z, _
  545.         DiffuseKr, DiffuseKg, DiffuseKb, _
  546.         AmbientKr, AmbientKg, AmbientKb, _
  547.         SpecularK, SpecularN, _
  548.         Points(1).coord(1), Points(1).coord(2), Points(1).coord(3), _
  549.         Points(2).coord(1), Points(2).coord(2), Points(2).coord(3), _
  550.         Points(3).coord(1), Points(3).coord(2), Points(3).coord(3), _
  551.         x4, y4, z4, _
  552.         Normals(1).coord(1), Normals(1).coord(2), Normals(1).coord(3), _
  553.         Normals(2).coord(1), Normals(2).coord(2), Normals(2).coord(3), _
  554.         Normals(3).coord(1), Normals(3).coord(2), Normals(3).coord(3), _
  555.         Nx4, Ny4, Nz4, _
  556.         Points(1).trans(1), Points(1).trans(2), _
  557.         Points(2).trans(1), Points(2).trans(2), _
  558.         Points(3).trans(1), Points(3).trans(2), _
  559.         Tx4, Ty4
  560. End Sub
  561. ' Return the minimum and maximum distances
  562. ' from the light source to points on this polygon.
  563. '
  564. ' This may not be the minimum distance to the
  565. ' plane, but it is close.
  566. Public Sub GetRminRmax(ByRef Rmin As Single, ByRef Rmax As Single, ByVal light_x As Single, ByVal light_y As Single, ByVal light_z As Single)
  567. Dim i As Integer
  568. Dim dx As Single
  569. Dim dy As Single
  570. Dim dz As Single
  571. Dim dist2 As Single
  572.  
  573.     Rmin = 1E+30
  574.     Rmax = -1E+30
  575.  
  576.     ' Do nothing if we are culled.
  577.     If IsCulled Then Exit Sub
  578.     If NumPts < 3 Then Exit Sub
  579.  
  580.     ' Get the min and max distance squared.
  581.     For i = 1 To NumPts
  582.         dx = light_x - Points(i).coord(1)
  583.         dy = light_y - Points(i).coord(2)
  584.         dz = light_z - Points(i).coord(3)
  585.         dist2 = dx * dx + dy * dy + dz * dz
  586.  
  587.         If Rmin > dist2 Then Rmin = dist2
  588.         If Rmax < dist2 Then Rmax = dist2
  589.     Next i
  590.  
  591.     ' Take square roots.
  592.     Rmin = Sqr(Rmin)
  593.     Rmax = Sqr(Rmax)
  594. End Sub
  595. ' Cull if any points are behind the center of
  596. ' projection.
  597. Public Sub ClipEye(ByVal R As Single)
  598. Dim pt As Integer
  599.  
  600.     ' Do nothing if we are already culled.
  601.     If IsCulled Then Exit Sub
  602.  
  603.     For pt = 1 To NumPts
  604.         If Points(pt).trans(3) >= R Then Exit For
  605.     Next pt
  606.  
  607.     If pt <= NumPts Then IsCulled = True
  608. End Sub
  609. ' Perform backface removal for the center
  610. ' of projection (X, Y, Z).
  611. Public Sub Cull(ByVal X As Single, ByVal Y As Single, ByVal Z As Single)
  612. Dim Ax As Single
  613. Dim Ay As Single
  614. Dim Az As Single
  615. Dim Nx As Single
  616. Dim Ny As Single
  617. Dim Nz As Single
  618.  
  619.     ' Compute a normal to the face.
  620.     NormalVector Nx, Ny, Nz
  621.  
  622.     ' Compute a vector from the center of
  623.     ' projection to the face.
  624.     Ax = Points(1).coord(1) - X
  625.     Ay = Points(1).coord(2) - Y
  626.     Az = Points(1).coord(3) - Z
  627.  
  628.     ' See if the vectors meet at an angle < 90.
  629.     IsCulled = (Ax * Nx + Ay * Ny + Az * Nz > -0.0001)
  630. End Sub
  631. ' Return the largest transformed Z value for this face.
  632. Public Function zmax() As Single
  633. Dim i As Integer
  634. Dim z_max As Single
  635.  
  636.     z_max = -1E+30
  637.     If IsCulled Then Exit Function
  638.  
  639.     For i = 1 To NumPts
  640.         If z_max < Points(i).trans(3) _
  641.             Then z_max = Points(i).trans(3)
  642.     Next i
  643.  
  644.     zmax = z_max
  645. End Function
  646.  
  647.  
  648.